package options

import (
	"cs0512/fmr/internal/pkg/server"
	"fmt"
	"path"
)

// Https启动配置选项
type SecureServingOptions struct {
	BindAddress string `json:"bind-address" mapstructure:"bind-address"`
	// 设置监听器时，BindPort被忽略，即使0也会提供HTTPS。
	BindPort int `json:"bind-port"    mapstructure:"bind-port"`
	// Required设置为true时，BindPort不能为零。
	Required bool
	// ServerCert TLS证书
	ServerCert GeneratableKeyCert `json:"tls"          mapstructure:"tls"`
	// AdvertiseAddress net.IP
}

// CertKey 包含与证书相关的配置项。
type CertKey struct {
	// CertFile 包含pem编码证书的文件，也可能还包含完整的证书链
	CertFile string `json:"cert-file"        mapstructure:"cert-file"`
	// KeyFile 由CertFile指定的证书的pem编码的私钥
	KeyFile string `json:"private-key-file" mapstructure:"private-key-file"`
}

// GeneratableKeyCert 证书相关的配置项
type GeneratableKeyCert struct {
	// 显式设置cert/Key文件。
	CertKey CertKey `json:"cert-key" mapstructure:"cert-key"`

	// 如果没有显式设置，certdirkery为默认的证书目录
	CertDirectory string `json:"cert-dir"  mapstructure:"cert-dir"`

	// 默认证书名称 CertDirectory/PairName.crt和CertDirectory/PairName.key
	PairName string `json:"pair-name" mapstructure:"pair-name"`
}

// 创建实例
func NewSecureServingOptions() *SecureServingOptions {
	return &SecureServingOptions{
		BindAddress: "0.0.0.0",
		BindPort:    8443,
		Required:    true,
		ServerCert: GeneratableKeyCert{
			PairName:      "appdemo",
			CertDirectory: "./cert",
		},
	}
}

// 将options选项写入配置中
func (s *SecureServingOptions) ApplyTo(c *server.Config) error {
	c.SecureServing = &server.SecureServingInfo{
		BindAddress: s.BindAddress,
		BindPort:    s.BindPort,
		CertKey: server.CertKey{
			CertFile: s.ServerCert.CertKey.CertFile,
			KeyFile:  s.ServerCert.CertKey.CertFile,
		},
	}
	return nil
}

func (s *SecureServingOptions) Complete() error {
	if s == nil || s.BindPort == 0 {
		return nil
	}

	keyCert := &s.ServerCert.CertKey
	if len(keyCert.CertFile) != 0 || len(keyCert.KeyFile) != 0 {
		return nil
	}

	if len(s.ServerCert.CertDirectory) > 0 {
		if len(s.ServerCert.PairName) == 0 {
			return fmt.Errorf("--secure.tls.pair-name is required if --secure.tls.cert-dir is set")
		}
		keyCert.CertFile = path.Join(s.ServerCert.CertDirectory, s.ServerCert.PairName+".crt")
		keyCert.KeyFile = path.Join(s.ServerCert.CertDirectory, s.ServerCert.PairName+".key")
	}

	return nil
}
